/*
 * stack.c
 *
 *  Created on: Apr 18, 2013
 *      Author: b
 */

#include "stack.h"


/*
 * Function		:	initStack
 *
 * Authors		:	BAYRAMOV Matin
 *
 * Parameters	:	Stack ** stack - a stack pointer
 *
 * Return		:	STACK_NON_NULL - if stack is not null
 * 				:	PROBLEME_MEMOIRE - if there is a memory problem
 * 				:	RES_OK - it's OK
 *
 * Description 	:	To initialize the stack
 *
 * Complexity	:	O(1)
 */
int initStack(Stack **stack) {

	// Must be null
	if ((*stack) != NULL) {
		printf("Attention, stack is not null - initStack\n");
		return STACK_NON_NULL;
	}

	// Create a new stack
	(*stack) = (Stack *) malloc ( sizeof ( Stack ) );

	if ((*stack) == NULL) {
		return PROBLEME_MEMOIRE;
	}

	// Initialize stack
	(*stack)->size = 0;
	(*stack)->items = NULL;

	return RES_OK;
}

/*
 * Function		:	pushStack
 *
 * Authors		:	BAYRAMOV Matin
 *
 * Parameters	:	Stack * stack - a stack
 * 				:	int item - item to add into the stack
 *
 * Return		:	STACK_NULL - if stack is null
 * 				:	PROBLEME_MEMOIRE - if there is a memory problem
 * 				:	RES_OK - it's OK
 *
 * Description 	:	Push (add) an element to the top of the stack
 *
 * Complexity	:	O(1)
 */
int pushStack(Stack *stack, int item) {

	// Create stack if it is null
	if (stack == NULL) {
		printf("Attention - stack was null, created pushStack\n");
		return STACK_NULL;
	}


	// Increment stack size
	stack->size++;

	// Resize stack
	stack->items = (int *) realloc (stack->items, stack->size * sizeof(size_t));

	if (stack->items == NULL) {
		return PROBLEME_MEMOIRE;
	}

	// Add new item in it
	stack->items[stack->size - 1] = item;

	return RES_OK;
}


/*
 * Function		:	popStack
 *
 * Authors		:	BAYRAMOV Matin
 *
 * Parameters	:	Stack * stack - a stack
 *
 * Return		:	STACK_NULL - if stack is null
 * 				:	STACK_UNDERFLOW - if there is no item in the stack (underflow)
 * 				:	int stackTopValue - the value of the item on the top of stack
 *
 * Description 	: 	Remove the top item, and return it's value (pop function)
 *
 * Complexity	:	O(1)
 */
int popStack(Stack *stack) {

	// Whether stack exist or not
	if (stack == NULL) {
		printf("Attention, stack is null - popStack\n");
		return STACK_NULL;
	}

	// Is there any item in the stack
	if (stack->size == 0) {
		printf("Attention, stack is underflow - popStack\n");
		return STACK_UNDERFLOW;
	}

	// Decrement stack size
	stack->size--;

	// Get the top element
	int stackTopValue = stack->items[stack->size];

	// Resize stack
	stack->items = (int *) realloc (stack->items, stack->size * sizeof(size_t));

	return stackTopValue;
}

/*
 * Function		:	popStack
 *
 * Authors		:	BAYRAMOV Matin
 *
 * Parameters	:	Stack * stack - a stack
 * 					int item - item to remove
 *
 * Return		:	STACK_NULL - if stack is null
 * 				:	STACK_UNDERFLOW - if there is no item in the stack (underflow)
 * 				:	RES_OK - it's OK
 *
 * Description 	: 	Remove an specific item from stack. It removes all occurrence of
 * 					the item.
 *
 * Complexity	:	O(n2) - n is the number of elements in the stack
 */
int popStackItem(Stack *stack, int item) {

	// Whether stack exist or not
	if (stack == NULL) {
		printf("Attention, stack is null - cloneStack\n");
		return STACK_NULL;
	}

	// Is there any item in the stack
	if (stack->size == 0) {
		printf("Attention, stack is underflow - popStack\n");
		return STACK_UNDERFLOW;
	}

	int var, kar, size = stack->size;

	for (var = 0; var < size; var++) {

		// Element found
		if (stack->items[var] == item) {

			// Shifting values
			for (kar = var; kar < size - 1; kar++) {
				stack->items[kar] = stack->items[kar + 1];
			}
			popStack(stack);
			var = size;
		}
	}

	return RES_OK;
}


/*
 * Function		:	cloneStack
 *
 * Authors		:	BAYRAMOV Matin
 *
 * Parameters	:	Stack * stack - a stack
 * 					Stack ** stack - a stack pointer
 *
 * Return		:	STACK_NULL - if stack is null
 * 				:	STACK_NON_NULL - if the stack clone is not null
 * 				:	RES_OK - it's OK
 *
 * Description 	: 	Remove an specific item from stack
 *
 * Complexity	:	O(n) - n is the number of elements in the stack to clone
 */
int cloneStack(Stack *stack, Stack **clone) {

	// Whether stack exist or not
	if (stack == NULL) {
		printf("Attention, stack is null - cloneStack\n");
		return STACK_NULL;
	}

	// This must be null
	if ((*clone) != NULL) {
		printf("Attention, stack clone is not null - cloneStack\n");
		return STACK_NON_NULL;
	}

	initStack(clone);

	int var, size = stack->size;

	// Add all elements to it's clone
	for (var = 0; var < size; var++) {
		pushStack((*clone), stack->items[var]);
	}

	return RES_OK;
}

/*
 * Function		:	cloneStack
 *
 * Authors		:	BAYRAMOV Matin
 *
 * Parameters	:	Stack ** stack - a stack pointer
 *
 * Return		:	STACK_NULL - if stack is null
 * 				:	RES_OK - it's OK
 *
 * Description 	: 	Free a stack memory
 *
 * Complexity	:	O(1)
 */
int freeStack(Stack **stack) {

	// Is stack null or not
	if ((*stack) == NULL) {
		return STACK_NULL;
	}

	// Free stack memory
	if ((*stack)->items != NULL) {
		free((*stack)->items);

		(*stack)->items = NULL;
		(*stack)->size = 0;
	}

	// Set stack to null
	if (stack != NULL) {
		free((*stack));
		(*stack) = NULL;
	}

	return RES_OK;
}


/*
 * Function		:	printStack
 *
 * Authors		:	BAYRAMOV Matin
 *
 * Parameters	:	Stack * stack - a stack
 *
 * Return		:	STACK_NULL - if stack is null
 * 				:	STACK_UNDERFLOW - if stack is underflow
 * 				:	RES_OK - it's OK
 *
 * Description 	: 	Free a stack memory
 *
 * Complexity	:	O(n) - n is the number of items in the stack
 */
int printStack(Stack *stack) {

	// Whether stack exist or not
	if (stack == NULL) {
		printf("Attention, stack was null - printStack\n");
		return STACK_NULL;
	}

	// Is there any item in the stack
	if (stack->size == 0) {
		printf("Attention, stack is underflow - printStack\n");
		return STACK_UNDERFLOW;
	}

	size_t i = 0;
	printf("Stack content : ");
	while (i < stack->size) {
		printf("%d ", stack->items[i]);
		i++;
	}
	printf("\n");

	return RES_OK;
}
